/*
 * Copyright 2016-2019 yoara
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package yhao.infra.web.common.security.checkrequest;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import yhao.infra.apilist.JsonCommonCodeEnum;
import yhao.infra.web.common.security.checkrequest.annotation.CheckRequestAnnotation;
import yhao.infra.web.common.security.checkrequest.policy.CheckPolicy;
import yhao.infra.web.common.security.checkrequest.policy.CheckResult;
import yhao.infra.web.common.security.checkrequest.policy.SQLCheckPolicy;
import yhao.infra.web.common.security.checkrequest.policy.TagCheckPolicy;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import yhao.infra.apilist.ValidationForm;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 请求输入校验拦截器
 * @author yoara
 */
@Aspect
@Component
public class CheckRequestAop {
	@Around(value = "@annotation(ch)")
	public Object check(ProceedingJoinPoint joinPoint, CheckRequestAnnotation ch) throws Throwable {
		return doHandle(joinPoint,ch);
	}

	public Object doHandle(ProceedingJoinPoint joinPoint, CheckRequestAnnotation ch) throws Throwable {
		AnnotationProperty ap = initAnnotation(ch);
		Object[] args = joinPoint.getArgs();
		if(args==null||args.length==0){
			return joinPoint.proceed();
		}
		//设置输入
		for(Object arg:args){
			if(!(arg instanceof ValidationForm)){
				continue;
			}
			JSONObject object = (JSONObject)JSONObject.toJSON(arg);
			String[] paramKeys = ch.checkParams()!=null&&ch.checkParams().length>0?
					ch.checkParams():object.keySet().toArray(new String[]{});
			//设置校验策略
			List<CheckPolicy> policyList = initPolicys(ap);
			for(String paramKey:paramKeys){
				String paramValue = object.getString(paramKey);
				CheckResult result = doCheck(paramValue,policyList);
				//判断不符合过滤条件
				if(!result.isValid()){
					switch (ap.getDealType()){
						case REPLACE:
							BeanUtils.setProperty(arg,paramKey,result.getReplaceObject());
							break;
						case JSON:
							Map<String, Object> jsonResult = new HashMap<>();
							jsonResult.put("status", JsonCommonCodeEnum.E0006.getStatus());
							jsonResult.put("message", result.getMsg());
							jsonResult.put("result", result.getMsg());
							return JSON.toJSONString(jsonResult);
					}
				}
			}
		}
		return joinPoint.proceed();
	}

	/**设置注解值**/
	private AnnotationProperty initAnnotation(CheckRequestAnnotation ch) {
		AnnotationProperty ap = new AnnotationProperty();
		ap.setAnnotationProperty(ch);
		return ap;
	}

	/**判断过滤**/
	private CheckResult doCheck(String paramValue, List<CheckPolicy> policyList) {
		CheckResult result = new CheckResult();
		result.setCheckObject(paramValue);
		if(!StringUtils.isEmpty(paramValue)){
			for(CheckPolicy policy:policyList){
				//if(policy instanceof SensitiveCheckPolicy){
				//	//result.setHandler(wordIndexService);
				//}
				policy.doCheck(result);
				//已经检测到，则break返回
				if(!result.isValid()){
					break;
				}
			}
		}
		return result;
	}

	/**设置校验策略**/
	private List<CheckPolicy> initPolicys(AnnotationProperty ap)
			throws InstantiationException, IllegalAccessException, ClassNotFoundException {
		CheckRequestAnnotation.Policy[] policys = ap.getPolicy();
		List<CheckPolicy> policyList = new ArrayList<CheckPolicy>();
		for(CheckRequestAnnotation.Policy policy:policys){
			switch (policy){
				case TAG:
					policyList.add(new TagCheckPolicy());
					break;
				case SQL:
					policyList.add(new SQLCheckPolicy());
					break;
				//case SENSITIVE:
				//	policyList.add(new SensitiveCheckPolicy());
				//	break;
				case CUSTOM:
					String[] customPolicys = ap.getCustomPolicys();
					if(customPolicys!=null){
						for(String custom:customPolicys){
							policyList.add(
									(CheckPolicy) Class.forName(custom).newInstance());
						}
					}
			}
		}
		return policyList;
	}

	/**注解属性对象**/
	class AnnotationProperty{
		/**默认不校验任何策略**/
		private CheckRequestAnnotation.Policy[] policy;
		/**自定义策略**/
		private String[] customPolicys;
		/**配置需要校验的输入参数，参数若为空数组表示全部匹配*/
		private String[] checkParams;
		/**返回策略**/
		private CheckRequestAnnotation.DealType dealType;

		public CheckRequestAnnotation.DealType getDealType() {
			return dealType;
		}

		public String[] getCustomPolicys() {
			return customPolicys;
		}

		public CheckRequestAnnotation.Policy[] getPolicy() {
			return policy;
		}

		public String[] getCheckParams() {
			return checkParams;
		}

		public void setPolicy(CheckRequestAnnotation.Policy[] policy) {
			this.policy = policy;
		}

		public void setCustomPolicys(String[] customPolicys) {
			this.customPolicys = customPolicys;
		}

		public void setCheckParams(String[] checkParams) {
			this.checkParams = checkParams;
		}

		public void setDealType(CheckRequestAnnotation.DealType dealType) {
			this.dealType = dealType;
		}

		public void setAnnotationProperty(CheckRequestAnnotation annotation){
			if(annotation==null){
				return;
			}
			if(annotation.policy()!=null){
				policy = annotation.policy();
			}
			if(annotation.customPolicies()!=null){
				customPolicys = annotation.customPolicies();
			}
			if(annotation.checkParams()!=null){
				checkParams = annotation.checkParams();
			}
			if(annotation.dealType()!=null){
				dealType = annotation.dealType();
			}
		}
	}
}